#include "ota.h"
#include "n32g430_flash.h"
#include <string.h>
#include <log.h>

__attribute__((section(".deviceid"))) const uint8_t can_ota_device_id = 0;


// CRC32多项式
#define CRC32_POLYNOMIAL    0xEDB88320

// 全局变量
static uint32_t g_current_addr = APP_START_ADDR;
static OTA_FirmwareInfo g_firmware_info = {0};

// CRC32表
static uint32_t crc32_table[256];

// 初始化CRC32表
static void Init_CRC32_Table(void)
{
    for(uint32_t i = 0; i < 256; i++) {
        uint32_t c = i;
        for(uint32_t j = 0; j < 8; j++) {
            if(c & 1)
                c = CRC32_POLYNOMIAL ^ (c >> 1);
            else
                c = c >> 1;
        }
        crc32_table[i] = c;
    }
}

// 计算CRC32
uint32_t OTA_CalculateCRC32(uint32_t addr, uint32_t size)
{
    uint32_t crc = 0xFFFFFFFF;
    uint8_t *data = (uint8_t*)addr;
    
    for(uint32_t i = 0; i < size; i++) {
        crc = crc32_table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8);
    }
    
    return ~crc;
}

/**
 * @brief  计算缓冲区CRC32
 * @param  buffer: 数据缓冲区
 * @param  size: 数据大小
 * @return CRC32值
 */
uint32_t OTA_CalculateBufferCRC32(uint8_t *buffer, uint32_t size)
{
    uint32_t crc = 0xFFFFFFFF;
    
    for(uint32_t i = 0; i < size; i++) {
        crc = crc ^ buffer[i];
        for(uint8_t j = 0; j < 8; j++) {
            if(crc & 1) {
                crc = (crc >> 1) ^ 0xEDB88320;
            } else {
                crc = crc >> 1;
            }
        }
    }
    
    return ~crc;
}

// 初始化OTA
OTA_Status OTA_Init(void)
{
    // 初始化Flash
    FLASH_Unlock();
    FLASH_Flag_Status_Clear(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);

    // 初始化CRC32表
    Init_CRC32_Table();
  
    // 初始化固件信息
    memset(&g_firmware_info, 0, sizeof(OTA_FirmwareInfo));
    g_current_addr = APP_START_ADDR;
    
    return OTA_OK;
}

// 设置升级标志
OTA_Status OTA_SetUpgradeFlag(void)
{
    LOGI("Setting upgrade flag...\r\n");
    FLASH_Unlock();
    
    // 擦除标志位所在页
    if(FLASH_One_Page_Erase(FLASH_FLAG_ADDR) != FLASH_EOP) {
        LOGI("Failed to erase flag page!\r\n");
        FLASH_Lock();
        return OTA_ERROR_ERASE;
    }
    LOGI("Flag page erased\r\n");
    
    // 写入升级标志
    if(FLASH_Word_Program(FLASH_FLAG_ADDR, FLASH_UPGRADE_FLAG) != FLASH_EOP) {
        LOGI("Failed to write upgrade flag!\r\n");
        FLASH_Lock();
        return OTA_ERROR_WRITE;
    }
    LOGI("Upgrade flag written\r\n");
    
    // 验证写入的标志
    uint32_t flag = *(uint32_t*)FLASH_FLAG_ADDR;
    if(flag != FLASH_UPGRADE_FLAG) {
        LOGI("Flag verification failed! Read: 0x%08lX, Expected: 0x%08lX\r\n", 
               flag, FLASH_UPGRADE_FLAG);
        FLASH_Lock();
        return OTA_ERROR_VERIFY;
    }
    LOGI("Flag verification OK\r\n");
    
    FLASH_Lock();
    return OTA_OK;
}

// 检查升级标志
uint8_t OTA_CheckUpgradeFlag(void)
{
    uint32_t flag = *(uint32_t*)FLASH_FLAG_ADDR;
    return (flag == FLASH_UPGRADE_FLAG);
}

// 清除升级标志
OTA_Status OTA_ClearUpgradeFlag(void)
{
    LOGI("Clearing upgrade flag...\r\n");
    FLASH_Unlock();
    
    // 擦除标志位所在页
    if(FLASH_One_Page_Erase(FLASH_FLAG_ADDR) != FLASH_EOP) {
        LOGI("Failed to erase flag page!\r\n");
        FLASH_Lock();
        return OTA_ERROR_ERASE;
    }
    
    FLASH_Lock();
    return OTA_OK;
}

// 擦除应用程序区域
OTA_Status Erase_App_Area(uint32_t size)
{
    uint32_t page_count = (size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE;
    uint32_t addr = APP_START_ADDR;
  
    for(uint32_t i = 0; i < page_count; i++) {
        if(FLASH_One_Page_Erase(addr) != FLASH_EOP) {
            return OTA_ERROR_ERASE;
        }
        addr += FLASH_PAGE_SIZE;
    }
  
    return OTA_OK;
}


// 写入固件数据
OTA_Status OTA_Update(uint8_t *data, uint32_t size)
{
    // 检查大小是否合法
    if(size > APP_SIZE || size == 0) {
        LOGI("OTA update failed, size: %ld\r\n", size);
        return OTA_ERROR_SIZE;
    }
    
    // 检查大小是否4字节对齐
    if(size % 4 != 0) {
        LOGI("OTA update failed, size not 4-byte aligned: %ld\r\n", size);
        return OTA_ERROR_SIZE;
    }
    
    // 检查地址范围
    if(g_current_addr < APP_START_ADDR || 
       g_current_addr + size > APP_START_ADDR + APP_SIZE) {
        LOGI("OTA update failed, address out of range: %ld\r\n", g_current_addr);
        return OTA_ERROR_SIZE;
    }
    
    // 写入新固件
    for(uint32_t i = 0; i < size; i += 4) {
        uint32_t word = *(uint32_t*)(data + i);
        if(FLASH_Word_Program(g_current_addr + i, word) != FLASH_EOP) {
            LOGI("Flash write failed at offset 0x%lX\r\n", g_current_addr + i);
            return OTA_ERROR_WRITE;
        }
    }
    
    // 校验写入的数据
    for(uint32_t i = 0; i < size; i += 4) {
        uint32_t written = *(uint32_t*)(g_current_addr + i);
        uint32_t original = *(uint32_t*)(data + i);
        if(written != original) {
            LOGI("Flash write verification failed at offset 0x%lX\r\n", g_current_addr + i);
            return OTA_ERROR_VERIFY;
        }
    }
    
    g_current_addr += size;
    return OTA_OK;
}

// 跳转到应用程序
void OTA_JumpToApp(void)
{
    // 检查栈顶地址是否有效
    if(((*(__IO uint32_t*)APP_START_ADDR) & 0x2FFE0000) == 0x20000000) {
        // 关闭所有中断
        __disable_irq();
        
        // 获取复位处理函数地址
        uint32_t app_jump_addr = *(__IO uint32_t*)(APP_START_ADDR + 4);
        void (*app_reset_handler)(void) = (void*)app_jump_addr;
        
        // 设置程序栈指针
        __set_MSP(*(__IO uint32_t*)APP_START_ADDR);
        
        // 跳转到应用程序
        app_reset_handler();
    }
}

// 获取当前运行模式
RunMode_TypeDef OTA_GetRunMode(void)
{
    // 通过当前程序运行的地址来判断
    uint32_t current_pc;
    __asm volatile ("mov %0, pc" : "=r" (current_pc));
    
    if(current_pc >= APP_START_ADDR) {
        return RUN_MODE_APP;
    } else {
        return RUN_MODE_BOOT;
    }
} 